<template>
  <div class="common-tree">
    <div class="head" v-if="!hideHead">
      <div class="head-title">
        <div class="title">{{ title }}</div>
        <div class="head-right">
          <span v-if="!lazy" style="cursor: pointer; font-size: 16px">
            <!-- 如果是组件记得在click加上.native -->
            <span
              v-if="!allExpend && !hideExpand"
              @click="changExpend(true)"
              :title="'全部展开'"
              >全部展开</span
            >
            <span
              v-else-if="allExpend || (hideExpand && showShrink)"
              @click="changExpend(false)"
              :title="'全部收齐'"
              >全部收齐</span
            >
          </span>
          <el-popover
            width="90"
            v-model="popoverShowObj['headMoreIcon']"
            v-if="!hideHeadMoreBtn"
            placement="bottom"
            trigger="manual"
            popper-class="commomTreeMorePopover"
          >
            <i
              class="el-icon-more"
              slot="reference"
              v-clickoutside="popoverClose"
              @click="popoverClick('headMoreIcon')"
              style="
                position: relative;
                top: -3px;
                margin-left: 8px;
                transform: rotate(90deg);
                color: #999;
              "
            ></i>
            <div class="btn-group">
              <slot name="headMoreBtn"></slot>
            </div>
          </el-popover>
        </div>
      </div>
      <div class="search">
        <el-input
          v-model.trim="searchKey"
          @input="debounceSearchKeyInput"
          :placeholder="placeholder"
          :size="inputProps.size || 'mini'"
          clearable
          @clear="searchClear"
          suffix-icon="el-icon-search"
        ></el-input>
      </div>
      <div class="addRootBtn">
        <slot name="headAddBtn" :treeData="treeData"></slot>
      </div>
    </div>
    <div class="tree-wrap">
      <el-scrollbar v-loading="loading">
        <el-tree
          ref="tree"
          v-if="treeShow"
          :default-expand-all="allExpend"
          :lazy="lazy"
          :load="loadNode"
          :node-key="nodeKey"
          :default-expanded-keys="defaultExpandedKeys"
          :filter-node-method="filterNode"
          :data="treeData"
          :props="props"
          @node-click="handleNodeClick"
          :expand-on-click-node="false"
          v-bind="$attrs"
          v-on="$listeners"
        >
          <div
            class="custom-tree-node"
            slot-scope="{ node, data }"
            :class="customNodeClass(node, data)"
          >
            <div class="node-name">
              <slot name="customNode" :node="node" :data="data">
                <span :title="node.label">{{ node.label }}</span>
              </slot>
            </div>
            <el-popover
              width="90"
              v-if="showMoreBtn(node, data)"
              v-model="popoverShowObj[data[nodeKey]]"
              trigger="manual"
              placement="bottom"
              popper-class="commomTreeMorePopover"
            >
              <i
                class="el-icon-more"
                slot="reference"
                v-clickoutside="popoverClose"
                @click="popoverClick(data[nodeKey])"
                style="transform: rotate(90deg)"
              ></i>
              <div class="btn-group">
                <slot name="moreBtn" :node="node" :data="data"></slot>
              </div>
            </el-popover>
          </div>
        </el-tree>
      </el-scrollbar>
    </div>
  </div>
</template>
<script>
let { difference, debounce } = require("lodash");
import clickoutside from "../../../utli/clickoutside";
// import FoldUpIcon from "./svg-font-icon/FoldUp.svg";
// import FoldDownIcon from "./svg-font-icon/FoldDown.svg";
export default {
  directives: { clickoutside },
  // components: { FoldUpIcon, FoldDownIcon },
  props: {
    title: {
      type: String,
      default: "",
    },
    hideHead: {
      type: Boolean,
      default: false,
    },
    hideExpand: {
      type: Boolean,
      default: false,
    },
    showShrink: {
      type: Boolean,
      default: false,
    },
    hideHeadMoreBtn: {
      type: Boolean,
      default: true,
    },
    placeholder: {
      type: String,
      default: "请输入",
    },
    asyncMethod: {},
    defaultExpendMethod: {},
    hideMoreBtn: {
      type: Boolean | Function,
      default: false,
    },
    hideMoreBtnMethod: {}, // 不可删除，兼容以前的
    filterNodeMethod: {},
    props: {
      type: Object,
      default: () => {
        return {
          children: "childrenList",
          label: "name",
        };
      },
    },
    nodeKey: {
      type: String,
      default: "id",
    },
    lazy: {
      type: Boolean,
      default: false,
    },
    nodeCustomClass: {},
    isSelectDefaultNode: {
      type: Boolean,
      default: true,
    },
    defaultNode: {
      type: [Object, Function],
      default: (treeData = []) => {
        return treeData[0];
      },
    },
    inputProps: {
      type: Object,
      default: () => {
        return {};
      },
    },
  },
  data() {
    return {
      loading: false,
      treeData: [],
      treeShow: true,
      flagClear: false,
      defaultExpandedKeys: [],
      expandedKeys: [], // 保留新增删除时的展开状态
      currentNodeEmptyFlag: false,
      currentNode: null,
      searchKey: "",
      oldSearchKey: "",
      popoverShowObj: {},
      debounceSearchKeyInput: debounce(this.searchKeyInput, 500),
      allExpend: false,
    };
  },
  // watch: {
  // 	searchKey(newV, oldV) {
  // 		if (!this.lazy) {
  // 			if (!oldV) {
  // 				this.expandedKeys = this.getElTreeExpandedKeys(this.$refs.tree) || [];
  // 			} else if (!newV) {
  // 				this.defaultExpandedKeys = [].concat(this.expandedKeys);
  // 				this.treeShow = false;
  // 				this.$nextTick(() => {
  // 					this.treeShow = true;
  // 				});
  // 			}
  // 			this.$refs.tree.filter(this.searchKey);
  // 		}
  // 	},
  // },
  created() {
    if (!this.lazy) {
      this.getTreeData();
    }
  },
  methods: {
    showMoreBtn(node, data) {
      let type = typeof this.hideMoreBtn;
      if (type === "function") {
        return !this.hideMoreBtn(node, data);
      }
      if (this.hideMoreBtnMethod) {
        return !this.hideMoreBtnMethod(node, data);
      }
      return !this.hideMoreBtn;
    },
    customNodeClass(node, data) {
      if (!this.nodeCustomClass) {
        return "";
      }
      return this.nodeCustomClass(node, data);
    },
    searchKeyInput() {
      if (this.lazy) {
        this.getTreeData();
      } else {
        if (!this.oldSearchKey) {
          this.expandedKeys = this.getElTreeExpandedKeys(this.$refs.tree) || [];
          if (this.currentNode) {
            this.$refs.tree &&
              this.$refs.tree.setCurrentKey(this.currentNode[this.nodeKey]);
          }
        } else if (!this.searchKey) {
          this.defaultExpandedKeys = [].concat(this.expandedKeys);
          this.treeShow = false;
          let currentNode = this.$refs.tree && this.$refs.tree.getCurrentNode();
          this.$nextTick(() => {
            this.treeShow = true;
            setTimeout(() => {
              if (currentNode) {
                this.$refs.tree &&
                  this.$refs.tree.setCurrentKey(currentNode[this.nodeKey]);
              }
            });
          });
        }
        this.oldSearchKey = this.searchKey;
        this.$refs.tree.filter(this.searchKey);
      }
    },
    // 一键展开收齐
    changExpend(flag) {
      this.allExpend = flag;
      this.changeNodeExpanded(this.$refs.tree.store.root, this.allExpend);
    },
    changeNodeExpanded(node, expanded) {
      node.expanded = expanded;
      if (node.childNodes && node.childNodes.length) {
        node.childNodes.forEach((one) => {
          this.changeNodeExpanded(one, expanded);
        });
      }
    },
    // 节点懒加载
    loadNode(node, resolve) {
      if (node && node.level === 0) {
        this.refreshBefore();
      }
      Promise.resolve(this.asyncMethod(this.searchKey, node)).then((res) => {
        if (node && node.level === 0) {
          this.initDealTreeData(res);
        }
        resolve(res);
      });
    },
    refresh(flag) {
      return this.getTreeData(flag);
    },
    // 直接加载
    getTreeData(flag) {
      if (flag) {
        this.currentNodeEmptyFlag = true;
      }
      if (!this.asyncMethod) {
        return;
      }
      this.refreshBefore();
      this.loading = true;
      if (!this.lazy) {
        this.searchKey = "";
      } else {
        this.expandedKeys = [];
      }
      return Promise.resolve(this.asyncMethod(this.searchKey))
        .then((res) => {
          this.treeData = res;

          this.initDealTreeData(res);
        })
        .finally(() => {
          this.loading = false;
        });
    },
    refreshBefore() {
      // 刷新前，保留当前选择节点和展开状态
      this.currentNode = this.currentNodeEmptyFlag
        ? null
        : this.$refs.tree && this.$refs.tree.getCurrentNode();
      this.currentNodeEmptyFlag = false;
      if (!this.flagClear) {
        this.expandedKeys = this.getElTreeExpandedKeys(this.$refs.tree) || [];
      } else {
        this.flagClear = false;
      }
    },
    getElTreeExpandedKeys(treeInstance) {
      if (!treeInstance) {
        return undefined;
      }
      let nodeKey = treeInstance.nodeKey;
      let res = Object.values(treeInstance.store.nodesMap)
        .filter((one) => {
          return one.expanded;
        })
        .map((one) => one.data[nodeKey]);
      return res;
    },
    initDealTreeData(treeData) {
      if (!treeData.length) {
        this.$emit("nodeClick", {});
        return;
      }
      // 保留原展缩状态或展开第一级
      if (this.expandedKeys && this.expandedKeys.length) {
        this.defaultExpandedKeys = [].concat(this.expandedKeys);
      } else {
        this.expendLevel(treeData);
      }
      // 保留原选中或默认选中第一个节点
      this.$nextTick(() => {
        if (this.currentNode) {
          let node = this.currentNode;
          this.$refs.tree && this.$refs.tree.setCurrentKey(node[this.nodeKey]);
          this.handleNodeClick(node);
        } else if (this.isSelectDefaultNode) {
          let defaultNode = treeData[0];
          if (typeof this.defaultNode === "function") {
            defaultNode = this.defaultNode(treeData);
          } else if (this.defaultNode) {
            defaultNode = this.defaultNode;
          }
          this.$refs.tree &&
            this.$refs.tree.setCurrentKey(defaultNode[this.nodeKey]);
          this.handleNodeClick(defaultNode);
        }
      });
    },
    setCurrentKey(key) {
      this.$refs.tree && this.$refs.tree.setCurrentKey(key);
    },
    // 默认展开层级
    expendLevel(treeData) {
      this.defaultExpandedKeys = [];
      if (this.defaultExpendMethod && !this.lazy) {
        this.defaultExpandedKeys = this.defaultExpandedKeys.concat(
          this.defaultExpendMethod(treeData)
        );
      }
    },
    searchClear() {
      this.flagClear = true;
      this.getTreeData();
      this.$emit("searchClear");
    },
    filterNode(value, data) {
      if (!value) return true;
      if (this.filterNodeMethod) {
        return this.filterNodeMethod(value, data);
      }
      return (data[this.props.label] || "").indexOf(value) !== -1;
    },
    handleNodeClick(nodeData, node) {
      if (!node && nodeData) {
        node = this.$refs.tree.getNode(nodeData[this.nodeKey]);
      }
      this.$emit("nodeClick", nodeData, node);
    },
    popoverClose() {
      for (let key in this.popoverShowObj) {
        this.popoverShowObj[key] = false;
      }
    },
    popoverClick(nodeKey) {
      this.popoverClose();
      if (!(nodeKey in this.popoverShowObj)) {
        this.$set(this.popoverShowObj, nodeKey, true);
      } else {
        this.popoverShowObj[nodeKey] = !this.popoverShowObj[nodeKey];
      }
    },
  },
};
</script>
<style scoped>
.el-popover .commomTreeMorePopover {
  min-width: 90px !important;
  width: 90px !important;
  padding: 8px 0;
}
.el-popover .commomTreeMorePopover .btn-group .el-button button {
  width: 100%;
  text-align: center;
  height: 36px;
  line-height: 36px;
  margin: 0 !important;
  padding: 0;
  font-size: 14px;
  color: #000;
}
.el-popover .commomTreeMorePopover .btn-group .el-button button :hover {
  color: #386bd7;
  background: #f2f4f7;
}
</style>
<style scoped>
::v-deep * {
  box-sizing: border-box;
}

* {
  box-sizing: border-box;
}
.common-tree .head .head-title {
  display: flex;
  align-items: center;
  padding-right: 10px;
  padding-bottom: 12px;
  line-height: 24px;
}
.common-tree .head .head-title .title {
  flex: 1;
  color: #292929;
  font-size: 14px;
  line-height: 14px;
  padding-right: 4px;
}
.common-tree {
  height: 100%;
  display: flex;
  flex-direction: column;
}
.common-tree .head .search {
  margin-bottom: 4px;
}
.common-tree .head .addRootBtn ::v-deep button {
  height: 40px;
  padding: 0px;
  border: 0;
  text-align: left;
  font-size: 16px;
}
.common-tree .head .addRootBtn ::v-deep button span {
  margin-left: 8px;
  color: #505363;
}
.common-tree .tree-wrap {
  flex: 1;
  overflow: hidden;
}
.common-tree .tree-wrap .el-scrollbar {
  height: 100%;
}
.common-tree .tree-wrap .el-scrollbar ::v-deep .el-scrollbar__wrap {
  overflow-x: hidden;
}
::v-deep .el-tree-node {
  outline: none;
}

::v-deep .el-tree-node__content {
  height: 40px;
  font-size: 14px;
  padding-right: 8px;
  line-height: 40px;
}
.custom-tree-node {
  width: calc(100% - 28px);
  display: flex;
  align-items: center;
}
.node-name {
  flex: 1;
  overflow: hidden;
  cursor: pointer;
  text-overflow: ellipsis;
  white-space: nowrap;
}
</style>
